//-------------------------------------------------------------------
//	Copyright (c) 2013  Zhirnov Andrey
//	This file is part of the "Noise Library" project.
//	See copyright notice in "linNoiseCL.h".
//-------------------------------------------------------------------

#pragma once

#include <Includes.h>

namespace Noise
{

	SHARED_POINTER( CSource );



	//
	// Function Source
	//

	class CSource : protected CReferenced
	{
	// types
	public:
		enum EDefaultFunctions
		{
			DF_NOISEGEN		= 1 << 0,
			DF_CUBIC_MIX	= 1 << 1,
		};

		typedef pod_array<ESource>	source_types_t;

		struct TFunctionData
		{
			source_types_t		srcTypes;
			string				source;
			string				buildLog;
			EPixelFormat		format;
			int					usedFuncs;	// EDefaultFunctions
			///
			TFunctionData () : format(R), usedFuncs(0)
			{}

			void Clear ()
			{
				source.ClearMem();
				buildLog.ClearMem();
				format = R;
				usedFuncs = 0;
			}

			bool AddSourceType (ESource type)
			{
				FOR( i, srcTypes ) {
					if ( type == srcTypes[i] )
						return false;
				}
				srcTypes.PushBack( type );
				return true;
			}
		};

		struct TPreBuildData
		{
			typedef array< CSource *, TFastCopyStrategy< CSource *> >	sources_t;

		private:
			mutable sources_t	_aSources;
			
		public:
			TPreBuildData ()					{ _aSources.Reserve(100); }
			void Clear ()						{ _aSources.ClearMem(); }

			sources_t const & Sources() const	{ return _aSources; }

			void Push (CSource *src) const		{ _aSources.PushBack( src );  src->_id = _aSources.LastIndex(); }
		};


	// variables
	protected:
		uint	_id;


	// methods
	private:
		void _Release()							{ delete this; }

	public:
		CSource ();
		virtual ~CSource ();


		// outer interface //
		virtual void Delete ();

		virtual EResult GetInteger (ESourceQuery type, int *v, int count) const;

		virtual EResult SetArg (EArgument type, CSourcePtr src);
		virtual EResult SetArg (EArgument type, const int *v, int count);
		virtual EResult SetArg (EArgument type, const real *v, int count);
		
		virtual EResult GetArg (EArgument type, CSourcePtr &src) const;
		virtual EResult GetArg (EArgument type, int *v, int count) const;
		virtual EResult GetArg (EArgument type, real *v, int count) const;


		// inner interface //
		virtual CSourcePtr Clone () const = 0;

		virtual void PreBuild (const TPreBuildData &data) = 0;		// add source to array
		virtual bool BuildFunction (TFunctionData &data) = 0;		// build function source

		NATIVE(
		virtual float32 NativeFunction32 (const fvec3 &vPoint) = 0;	// calculate in native code
		virtual float64 NativeFunction64 (const dvec3 &vPoint) = 0;
		)

		// helpers //
		uint GetSourceId() const				{ return _id; }

		static const char * FunctionName ()		{ return "NFunc"; }
		static const char * FunctionArgs ()		{ return "( vPoint )"; }

		static string & BuildFunctionHeader (string &src, uint index)
		{
			src << "#define " << FunctionName() << index << FunctionArgs();
			return src;
		}

		static string & BuildFunctionCall (string &str, uint index)
		{
			str << FunctionName() << index << "( vPoint )"; 
			return str;
		}

		static bool HasColorOutput (CSourcePtr src)
		{
			int src_type = 0;
			src->GetInteger( SOURCE_TYPE, &src_type, 1 );
			return (src_type == RENDER_OUTPUT or
					src_type == GRADIENT or
					src_type == SWIZZLE);
		}
	};

}	// Noise
